package au.edu.unsw.editingtool.web;

import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import au.edu.unsw.editingtool.db.DBEditingpool;
import au.edu.unsw.editingtool.db.DBPublication;
import au.edu.unsw.editingtool.fedora.FedoraFactory;
import au.edu.unsw.editingtool.global.GlobalConstant;
import au.edu.unsw.editingtool.global.PropertyReader;
import au.edu.unsw.editingtool.transformxml.ValetXmlCreator;

/**
 * Servlet implementation class FormSubmit
 */
public class FormSubmit extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private String ServletContext = null;
	private String ApplicationContext = null;	
	private String ApplicationPath = null;
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FormSubmit() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doService(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doService(request, response);
	}
	
	
	protected void doService (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		ServletContext = getServletContext().getRealPath("") + GlobalConstant.fileSeparator;
		ApplicationContext = request.getLocalName()+":"+request.getServerPort()+"/"+
						GlobalConstant.APPLICATIONNAME+"/";
		ApplicationPath = request.getContextPath();
		System.out.println("==== [FORMSUBMIT Servlet] ====");
		
		HttpSession session = request.getSession(false);
		String sessionid = session.getId();
		String username = session.getAttribute(GlobalConstant.username).toString();
		String group = session.getAttribute(GlobalConstant.userGroup).toString();
		String controlcommand = (String) request.getParameter(GlobalConstant.requestCommand);
		String querystring = request.getQueryString();
		
		String pid = null;
		pid = (String) request.getAttribute(GlobalConstant.pid);
		if (pid ==null)
			pid = request.getParameter(GlobalConstant.pid);
						
		System.out.println("[FORMSUBMIT] requestCommand : "+controlcommand);
		System.out.println("[FORMSUBMIT] Delete editingpool record");
		// Delete the editing pool record
		
		if (controlcommand == null)			
		{			
			session.removeAttribute(GlobalConstant.requestFormData);						
			
			System.out.println("[FORMSUBMIT] Forward to "+GlobalConstant.JSPMain);
			session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdFormSubmit);
			RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPMain+"?"+querystring);
			rd.forward(request, response);	
			return;
		}
		else
		{
			// 1. Check Editing pool table if user can edit
			boolean isEditRecordExist = this.isEditExist(pid,sessionid);				
							
			if(isEditRecordExist)
			{									
				if(!this.canEdit(pid, username))
				{
					this.deleteEditRecord(pid, username, sessionid);
					System.out.println("[FORMSUBMIT] "+username+" can not ingest resource "+pid);
					System.out.println("[FORMSUBMIT] Forward to "+GlobalConstant.JSPError);					
					request.setAttribute(GlobalConstant.responseType,GlobalConstant.typeError);
					request.setAttribute(GlobalConstant.responseControl, GlobalConstant.cmdEdit);
					request.setAttribute(GlobalConstant.responseMsg, "Currently this resource "+pid+" is being edited by other user!");
					session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdFormSubmit);
					RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPError);
					rd.forward(request, response);
					return;
				}					
			}
			if(controlcommand.compareTo(GlobalConstant.cmdFormSubmit)!=0)
			{	
				session.removeAttribute(GlobalConstant.requestFormData);									
				this.deleteEditRecord(pid, username, sessionid);
				
				System.out.println("[FORMSUBMIT] Forward to "+GlobalConstant.JSPMain);
				session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdFormSubmit);
				RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPMain+"?"+querystring);
				rd.forward(request, response);
				return;
			}
			else
			{
				// Update data to repository
				try {	
					String fedora_version = "";
					
					ValetXmlCreator valetXML = new ValetXmlCreator();
					valetXML.createValetDocument("Session");
					valetXML.createFormDataElement();
						
					// Create VALETXML based on the Formdata Hashtable
					Hashtable<String, String> formData = (Hashtable<String,String>) session.getAttribute(GlobalConstant.requestFormData);
					if(formData !=null)
					{
						valetXML.createChildElementsWithContentsUsingHashtable(formData, GlobalConstant.valetDocFormData);					
					}
								
					// Get the configuration.
					PropertyReader configReader = null;						
					configReader = new PropertyReader();
					configReader.setFile(ServletContext + GlobalConstant.configFilePath);			
					configReader.buildConfiguration();			
						
					String fedoraHost = configReader.getConfigValue(new String[]{GlobalConstant.FEDORA,"host"})+":" + 
									configReader.getConfigValue(new String[]{GlobalConstant.FEDORA,"port"})+
									configReader.getConfigValue(new String[]{GlobalConstant.FEDORA,"path"});
					String fedora_username = configReader.getConfigValue(new String[]{GlobalConstant.FEDORA,"username"});
					String fedora_password = configReader.getConfigValue(new String[]{GlobalConstant.FEDORA,"password"});
					
					boolean isIngestOK = false;
					
					
					// Grab fedora version before update
					FedoraFactory fedora = new FedoraFactory(fedoraHost, fedora_username, fedora_password);
					String fedora_metadata=configReader.getConfigValue(new String[]{GlobalConstant.FEDORA,"metadata"});
					fedora_version = fedora.getDatastreamVersionID(pid, fedora_metadata);					
					System.out.println("[FORMSUBMIT] Current Fedora Version : "+fedora_version);
					
					// Metadata/resource name to update
					String[] metadatas = (configReader.getConfigValue(new String[]{GlobalConstant.TRANSFORM,"metadata"})).split(" ");
								
					// XSL file for transforming the metadata
					String[] xslfiles = (configReader.getConfigValue(new String[]{GlobalConstant.TRANSFORM,"tometadata"})).split(" ");
					
					// Both XSLs and metadatas has to be the same
					if(xslfiles.length==metadatas.length)
					{						
						for(int xslindex=0;xslindex<xslfiles.length;xslindex++)
						{							
							String xsl = ServletContext+
								configReader.getConfigValue(new String[]{GlobalConstant.TRANSFORM,"root"})+
								GlobalConstant.fileSeparator +
								configReader.getConfigValue(new String[]{GlobalConstant.TRANSFORM,"template"})+
								GlobalConstant.fileSeparator +
								xslfiles[xslindex];
					
							String metadata = metadatas[xslindex];
							
							System.out.println("[FORMSUBMIT] XSL = "+xsl);
							System.out.println("[FORMSUBMIT] Metadata = "+metadata);
							String date = null;
							
							// Update
							date = valetXML.fedoraUpdateMetadata(fedoraHost, fedora_username, fedora_password, 
									pid, metadata, formData.get("title"), xsl);
							if(date==null)
							{
								isIngestOK=false;
								break;
							}
							else
								isIngestOK=true;
						}
					}	
					
					if(!isIngestOK)
					{
						session.removeAttribute(GlobalConstant.requestFormData);
						this.deleteEditRecord(pid, username, sessionid);
						
						System.out.println("[FORMSUBMIT] Forward to "+GlobalConstant.JSPError);								
						request.setAttribute(GlobalConstant.responseType,GlobalConstant.typeError);
						request.setAttribute(GlobalConstant.responseControl, GlobalConstant.cmdFormSubmit);
						request.setAttribute(GlobalConstant.responseMsg, "Error in ingesting the resource to repository");
						request.setAttribute(GlobalConstant.pid, pid);
						session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdFormSubmit);
						RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPError+"?"+querystring);
						rd.forward(request, response);
						return;
					}
					else
					{			
						// Update publication record
						DBPublication dbpublication = new DBPublication();
						dbpublication.setConfFile(ServletContext + GlobalConstant.configFilePath);
						boolean isPublicationExist = dbpublication.getData(pid);
						boolean canCommit = false;
						if(!isPublicationExist)
						{
							dbpublication.setPublication(pid);
							dbpublication.setFedoraVersion(fedora_version);							
							canCommit = true;
						}
																			
						String publicationStatus = null;
						publicationStatus = dbpublication.getObjectStatus();
						if(publicationStatus==null)
							publicationStatus="";
						
						String dbFedoraVersion = (String) dbpublication.getFedoraVersion();
						if(dbFedoraVersion==null)
							dbFedoraVersion="";
						System.out.println("fedora version in db : "+dbFedoraVersion);
						
						if(dbFedoraVersion.length()==0 || publicationStatus.compareTo(GlobalConstant.objectApproved)==0)
						{
							dbpublication.setFedoraVersion(fedora_version);	
						}
						
						if(group.compareTo(GlobalConstant.groupUser)==0)
						{							
							if(publicationStatus.compareTo(GlobalConstant.objectReview)!=0)
							{
									dbpublication.setObjectStatus(GlobalConstant.objectNew);
									dbpublication.setEditor(username);
							}
							canCommit = true;
						}
						else if(group.compareTo(GlobalConstant.groupReview)==0)
						{
							dbpublication.setLastReviewer(dbpublication.getCurrentReviewer());
							dbpublication.setCurrentReviewer(username);
							if(publicationStatus.compareTo(GlobalConstant.objectNew)==0 || publicationStatus.compareTo(GlobalConstant.objectReview)==0)
							{								
								dbpublication.setObjectStatus(request.getParameter(GlobalConstant.ObjectStatus).toString());
							}
							canCommit = true;
						}
						else if(group.compareTo(GlobalConstant.groupAdmin)==0 && group.compareTo(GlobalConstant.groupSysAdmin)==0)
						{
							canCommit = false;
						}
						else
						{
							canCommit = false;
						}
						
						if (canCommit)
						{
							System.out.println("[FORMSUBMIT] DBPUBLICATION commit");
							dbpublication.commit();
						}
						
						System.out.println("[FORMSUBMIT] Forward to "+GlobalConstant.JSPSubmit);
						this.deleteEditRecord(pid, username, sessionid);
						session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdFormSubmit);
						request.setAttribute(GlobalConstant.pid, pid);
						RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPSubmit+"?"+querystring);
						rd.forward(request, response);
						return;
					}
				}
				catch (Exception ex)
				{								
					DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
			        Date date = new Date();
			        String currdate = dateFormat.format(date);
			        this.deleteEditRecord(pid, username, sessionid);
					System.out.println("[FORMSUBMIT] ERROR ============ "+currdate);
					System.out.println("[FORMSUBMIT] Forward to "+GlobalConstant.JSPError);								
					request.setAttribute(GlobalConstant.responseType,GlobalConstant.typeError);
					request.setAttribute(GlobalConstant.responseControl, GlobalConstant.cmdFormSubmit);
					request.setAttribute(GlobalConstant.responseMsg, "Error in ingesting the resource to repository");
					session.setAttribute(GlobalConstant.requestLastCommand,GlobalConstant.cmdFormSubmit);
					request.setAttribute(GlobalConstant.pid, pid);
					RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPError+"?"+querystring);
					rd.forward(request, response);
					ex.printStackTrace();
					return;
				} 
			}				
		}
	}	
	private void deleteEditRecord(String pid, String username, String sessionid)
	{
		DBEditingpool dbeditingpool = new DBEditingpool();
		dbeditingpool.setConfFile(ServletContext + GlobalConstant.configFilePath);
		try {
			dbeditingpool.deleteRecord(pid, username, sessionid);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private boolean isEditExist(String pid,String sessionid)
	{
		boolean result = false;
		DBEditingpool dbeditingpool = new DBEditingpool();
		dbeditingpool.setConfFile(ServletContext + GlobalConstant.configFilePath);
		try {
			result = dbeditingpool.isExist(pid, sessionid);
		} 
		catch (Exception e) {			
			e.printStackTrace();
		}
		return result;	
	}
	
	private boolean canEdit(String pid, String username)
	{
		boolean result = false;		
		String dbusername = null;
		DBEditingpool dbeditingpool = new DBEditingpool();
		dbeditingpool.setConfFile(ServletContext + GlobalConstant.configFilePath);
		try 
		{
			dbusername = dbeditingpool.getUsername(pid);
			if(dbusername!=null && username.compareTo(dbusername)==0)
			{
				result=true;
			} 			
		}		
		catch (Exception e) {			
			e.printStackTrace();
		}
		return result;
	}
}
